package ishaportalunittests.apis.admin;

import static org.junit.Assert.assertTrue;
import gwtappcontainer.server.apis.admin.AdminAPI;
import gwtappcontainer.server.apis.admin.Roles.Role;
import gwtappcontainer.shared.apis.APIResponse;
import gwtappcontainer.shared.apis.APIResponse.Status;
import gwtappcontainer.shared.apis.admin.RoleProp;

import ishaportalunittests.helpers.MockGateKeeper;

import java.util.List;
import java.util.UUID;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserServiceFactory;
import com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig;
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
import com.google.appengine.tools.development.testing.LocalUserServiceTestConfig;

public class AdminAPIRoleTest {

    private final LocalServiceTestHelper dsHelper =
        new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig());
    
    private final LocalServiceTestHelper userServiceHelper =
	        new LocalServiceTestHelper(new LocalUserServiceTestConfig())
	            .setEnvIsAdmin(true).setEnvIsLoggedIn(true)
	            .setEnvAuthDomain("example.com")
	            .setEnvEmail("test@example.com");

    @Before
    public void setUp() {
        dsHelper.setUp();
        userServiceHelper.setUp();
    }

    @After
    public void tearDown() {
    	userServiceHelper.tearDown();     
        //dsHelper.tearDown();        
    }
    
    @Test
    public void anyRoleModificationWithoutLoginGivesAuthenticationError() {
    	AdminAPI api = new AdminAPI();
    	
    	APIResponse resp = api.addRole("dummy", null);
    	assertTrue(resp.statusCode == Status.ERROR_LOGIN_REQUIRED);
    	
    	resp = api.deleteRole("dummy", null);
    	assertTrue(resp.statusCode == Status.ERROR_LOGIN_REQUIRED);
    	
    	resp = api.renameRole("dummy", "dummy_new", null);
    	assertTrue(resp.statusCode == Status.ERROR_LOGIN_REQUIRED);
    }
    
	@SuppressWarnings("unchecked")
	@Test
    public void developerCanAddUpdateDeleteRole() {
    	//1. create a gatekeeper that allows developer
    	//2. add a role and ensure it is present
    	//3. rename a role and ensure the entity in datastore is updated
    	//4. delete the role and ensure it is deleted from datastore
    	
    	//1. create a gatekeeper and assign test@example.com as developer
		MockGateKeeper mockGateKeeper = new MockGateKeeper();
		mockGateKeeper.allowRoleToUser("test@example.com", Role.DEVELOPER);
		
    	AdminAPI api = new AdminAPI();    	
    	api.setGateKeeper(mockGateKeeper);
    	
    	//2. add a role and ensure it is present
    	User user = UserServiceFactory.getUserService().getCurrentUser();
    	String role = "testdummy_" + UUID.randomUUID();
    	APIResponse resp = api.addRole(role, user);
    	assertTrue(resp.statusCode == Status.SUCCESS);
    	
		List<RoleProp> roles = (List<RoleProp>) api.getAllRoles().object;
		
		assertTrue("added role should be present", 
    			isRolePresent(roles, role.toUpperCase()));   
    	
    	//3. rename a role and ensure the entity in datastore is updated
    	String newRole = role + "_new";
    	resp = api.renameRole(role, newRole, user);
    	assertTrue(resp.statusCode == Status.SUCCESS);      
    	
    	roles = (List<RoleProp>) api.getAllRoles().object;
    	    	
    	assertTrue("new role should be present", 
    			isRolePresent(roles, newRole.toUpperCase()));    	    	
    	assertTrue("old role should not be present",
    			(false == isRolePresent(roles, role.toUpperCase())));
    	
    	//4. delete the role and ensure it is deleted from datastore
    	resp = api.deleteRole(newRole, user);
    	assertTrue("deletion should be success", 
    			resp.statusCode == Status.SUCCESS);
    	roles = (List<RoleProp>) api.getAllRoles().object;
    	assertTrue("role after deletion should not be present",
    			(false == isRolePresent(roles, newRole.toUpperCase())));
    }
	
	@Test
	public void loginNotRequiredToViewRoles() {
		//1. create a gatekeeper that allows developer
		MockGateKeeper mockGateKeeper = new MockGateKeeper();
		mockGateKeeper.allowRoleToUser("test@example.com", Role.DEVELOPER);
    	AdminAPI api = new AdminAPI();
    	api.setGateKeeper(mockGateKeeper);
    	
    	User user = UserServiceFactory.getUserService().getCurrentUser();
    	String role = "dummy_" + UUID.randomUUID();
    	APIResponse resp = api.addRole(role, user);
    	assertTrue(resp.statusCode == Status.SUCCESS);
    	
    	userServiceHelper.setEnvIsLoggedIn(false);
    	user = UserServiceFactory.getUserService().getCurrentUser();
    	assertTrue(null == user);
    	
    	@SuppressWarnings("unchecked")
		List<RoleProp> all= (List<RoleProp>)api.getAllRoles().object;
    	    	
    	assertTrue(isRolePresent(all, role.toUpperCase()));
	}
	
	@Test
    public void nonDeveloperCannotAddUpdateDeleteRole() {
    	//1. create a gatekeeper that allows portal_admin
    	//2. add a role and ensure it gives status code as insufficient permission
    	//3. rename a role and ensure it gives status code as insufficient permission 
		//3. delete a role and ensure it gives status code as insufficient permission 
    	
    	//1. create a gatekeeper that allows developer
		MockGateKeeper mockGateKeeper = new MockGateKeeper();
		mockGateKeeper.allowRoleToUser("test@example.com", Role.PORTAL_ADMIN);
    	AdminAPI api = new AdminAPI();
    	api.setGateKeeper(mockGateKeeper);
    	
    	//2. add a role 
    	User user = UserServiceFactory.getUserService().getCurrentUser();
    	String role = "testdummy";
    	APIResponse resp = api.addRole(role, user);
    	assertTrue("add should give insufficient permission error", 
    			resp.statusCode == Status.ERROR_INSUFFICIENT_PERMISSION);
    	
    	//3. rename a role
    	resp = api.renameRole(role, role + "_new", user);
    	assertTrue("rename should give insufficient permission error", 
    			resp.statusCode == Status.ERROR_INSUFFICIENT_PERMISSION);
    	
    	//4. delete a role
    	resp = api.deleteRole(role, user);
    	assertTrue("delete should give insufficient permission error", 
    			resp.statusCode == Status.ERROR_INSUFFICIENT_PERMISSION);    	    
    }
    

	@Test
    public void roleSavedInUpperCase() {
    	AdminAPI api = new AdminAPI();
    	MockGateKeeper mockGateKeeper = new MockGateKeeper();
		mockGateKeeper.allowRoleToUser("test@example.com", Role.DEVELOPER);
    	api.setGateKeeper(mockGateKeeper);
    	    	    	
    	User user = UserServiceFactory.getUserService().getCurrentUser();
    	api.addRole("testdummy", user);
    	
    	@SuppressWarnings("unchecked")
		List<RoleProp> roles = (List<RoleProp>) api.getAllRoles().object;
    	    	
    	assertTrue(isRolePresent(roles, "TESTDUMMY"));    	    	
    }
    
    private boolean isRolePresent(List<RoleProp> roles, String role) {    	
    	for (RoleProp roleProp : roles) {
			if (roleProp.name.equals(role))
				return true;
		}
    	
    	return false;
    }
}